package com.lpf.MyGameSaveBackup.alist.service;


import cn.hutool.core.convert.Convert;
import cn.hutool.log.StaticLog;
import com.alibaba.fastjson.JSONObject;
import com.lpf.MyGameSaveBackup.alist.constants.InterfaceListConstants;
import com.lpf.MyGameSaveBackup.config.service.GlobalConfigService;
import com.lpf.MyGameSaveBackup.utils.HttpCilentUtil;
import com.lpf.MyGameSaveBackup.utils.ResponseVo;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class AlistService {
    private static String token;

    //获取用户token
    public static String getToken(String username,String password,String otp_code){
        if (StringUtils.isEmpty(username)){
            StaticLog.error("获取alist服务鉴权失败，username不能为空");
        }
        if (StringUtils.isEmpty(password)){
            StaticLog.error("获取alist服务鉴权失败，password不能为空");
        }

        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.AUTH_LOGIN;
        Map<String, Object> paramMap = new HashMap<>();
        //用户名
        paramMap.put("username",username);
        //密码
        paramMap.put("password",password);
        //二步验证码
        if (StringUtils.isNotEmpty(otp_code)){
            paramMap.put("otp_code",otp_code);
        }
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-Type", "application/json");
        headerMap.put("Accept", "application/json");
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                token = resultBody.getJSONObject("data").getString("token");
            }
            else {
                StaticLog.error("获取alist服务鉴权失败，接口调用失败：{}",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("获取alist服务鉴权失败，接口调用异常：{}",e);
        }
        return token;
    }

    //通过全局配置的用户信息获取用户token
    public static String getToken(boolean refresh){
        String username = GlobalConfigService.GlobalConfig.getAlistUsername();
        String password = GlobalConfigService.GlobalConfig.getAlistPassword();
        String otp_code = GlobalConfigService.GlobalConfig.getAlistOtpCode();
        //强制刷新或者token为空，获取token
        if (refresh || StringUtils.isEmpty(token)){
            return getToken(username,password,otp_code);
        }
        else
            return token;
    }
    public static String getToken(){
        return getToken(false);
    }

    public static Map<String, String> getHeaderMap(){
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-Type", "application/json");
        headerMap.put("Accept", "application/json");
        headerMap.put("Authorization", getToken());
        return headerMap;
    }

    //列出文件目录
    public static JSONObject fsList(String path,String password,Integer page,Integer per_page,Boolean refresh){
        if (StringUtils.isEmpty(path)){
            StaticLog.error("列出文件目录信息失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_LIST;
        Map<String, Object> paramMap = new HashMap<>();
        //路径
        paramMap.put("path",path);
        //密码
        paramMap.put("password",StringUtils.isNotEmpty(password) ? password : "");
        //页数
        paramMap.put("page",null == page ? 1 : page);
        //每页数目 传0返回全部
        paramMap.put("per_page",null == per_page ? 0 : per_page);
        //强制刷新
        paramMap.put("refresh",null == refresh ? false : refresh);
        Map<String, String> headerMap = getHeaderMap();
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                return resultBody.getJSONObject("data");
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("列出文件目录失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return fsGet(path,password,page,per_page,refresh);
            }
            else {
                StaticLog.error("列出文件目录失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("列出文件目录失败，接口调用异常：{}",e);
        }
        return null;
    }

    //获取某个文件/目录信息
    public static JSONObject fsGet(String path,String password,Integer page,Integer per_page,Boolean refresh){
        if (StringUtils.isEmpty(path)){
            StaticLog.error("获取某个文件/目录信息失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_GET;
        Map<String, Object> paramMap = new HashMap<>();
        //路径
        paramMap.put("path",path);
        //密码
        paramMap.put("password",StringUtils.isNotEmpty(password) ? password : "");
        paramMap.put("page",null == page ? 1 : page);
        paramMap.put("per_page",null == per_page ? 0 : per_page);
        //强制 刷新
        paramMap.put("refresh",null == refresh ? false : refresh);
        Map<String, String> headerMap = getHeaderMap();
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                return resultBody.getJSONObject("data");
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("获取某个文件/目录信息失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return fsGet(path,password,page,per_page,refresh);
            }
            else {
                StaticLog.error("获取某个文件/目录信息失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("获取某个文件/目录信息失败，接口调用异常：{}",e);
        }
        return null;
    }

    public static JSONObject fsGet(String path,Boolean refresh){
        return fsGet(path,null,null,null,refresh);
    }

    //文件下载
    public static boolean downloadFile(String downloadPath,String savePath){
        String rawUrl = fsGet(downloadPath,true).getString("raw_url");
        if (StringUtils.isEmpty(rawUrl)){
            StaticLog.error("获取不到文件下载路径");
        }
        InputStream inputStream = HttpCilentUtil.sendRequest_InputStream(rawUrl,"GET",null,null);
        if (null != inputStream){
            try {
                File saveFile = new File(savePath);
                //如果存放路径是一个文件夹，获取到下载文件的文件名作为存放文件的文件名
                if (saveFile.isDirectory()){
                    String path = new URL(rawUrl).getPath();
                    String fileName = path.substring(path.lastIndexOf("/")+1,path.length());
                    saveFile = new File(saveFile.getAbsolutePath()+ File.separator + fileName);
                }
                //避免有重名文件存在，先删除
                saveFile.deleteOnExit();
                //写入到存放路径
                FileOutputStream out = new FileOutputStream(saveFile);
                IOUtils.copy(inputStream, out);
                return true;
            }
            catch (Exception e){
                e.printStackTrace();
                StaticLog.error("文件下载失败，写入到本地异常：{}",e);
            }
        }
        else {
            StaticLog.error("文件下载失败，文件不存在");
        }
        return false;
    }

    //新建文件夹
    public static boolean fsMkdir(String path){
        if (StringUtils.isEmpty(path)){
            StaticLog.error("新建文件夹失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_MKDIR;
        Map<String, Object> paramMap = new HashMap<>();
        //路径
        paramMap.put("path",path);
        Map<String, String> headerMap = getHeaderMap();
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                return true;
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("新建文件夹失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return fsMkdir(path);
            }
            else {
                StaticLog.error("新建文件夹失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("新建文件夹失败，接口调用异常：{}",e);
        }
        return false;
    }

    //重命名文件
    public static boolean fsRename(String name,String path){
        if (StringUtils.isEmpty(name)){
            StaticLog.error("重命名文件失败，name不能为空");
        }
        if (StringUtils.isEmpty(path)){
            StaticLog.error("重命名文件失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_RENAME;
        Map<String, Object> paramMap = new HashMap<>();
        //目标文件名 如：test3
        paramMap.put("name",name);
        //源文件路径 如：/阿里云盘/test2
        paramMap.put("path",path);
        Map<String, String> headerMap = getHeaderMap();
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                return true;
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("重命名文件失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return fsRename(name,path);
            }
            else {
                StaticLog.error("重命名文件失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("重命名文件失败，接口调用异常：{}",e);
        }
        return false;
    }

    //文件上传
    public static JSONObject uploadFile(String path,File file,Boolean isTask){
        if (null == file){
            StaticLog.error("文件上传失败，file不能为空");
        }
        if (StringUtils.isEmpty(path)){
            StaticLog.error("文件上传失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_Form;
        Map<String, Object> paramMap = new HashMap<>();
        //文件
        paramMap.put("file",file);
        Map<String, String> headerMap = getHeaderMap();
        //必须是form-data格式
        headerMap.put("Content-Type","multipart/form-data");
        //经过URL编码的完整文件路径
        headerMap.put("File-Path",path);
        //文件大小
        headerMap.put("Content-Length", Convert.toStr(file.length()));
        //是否添加为任务
        headerMap.put("As-Task",null == isTask ? "false" : Convert.toStr(isTask));
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"PUT",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                JSONObject data = resultBody.getJSONObject("data");
                //如果As-Task传false，接口返回的data是空，如果As-Task=true,data是任务信息
                if (null == data){
                    data =  new JSONObject();
                }
                return data;
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("文件上传失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return uploadFile(path,file,isTask);
            }
            else {
                StaticLog.error("文件上传失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("文件上传失败，接口调用异常：{}",e);
        }
        return null;
    }


    //删除文件
    public static boolean del(String name,String path){
        if (StringUtils.isEmpty(name)){
            StaticLog.error("删除文件失败，name不能为空");
        }
        if (StringUtils.isEmpty(path)){
            StaticLog.error("删除文件失败，path不能为空");
        }
        String url = GlobalConfigService.GlobalConfig.getAlistUrl() + InterfaceListConstants.FS_REMOVE;
        Map<String, Object> paramMap = new HashMap<>();
        //目标文件名 如：test3
        paramMap.put("names", Arrays.asList(name.split(",")));
        //源文件路径 如：/阿里云盘/test2
        paramMap.put("dir",path);
        Map<String, String> headerMap = getHeaderMap();
        try {
            ResponseVo result = HttpCilentUtil.sendRequestWithHeader(url,"POST",paramMap,headerMap,null);
            JSONObject resultBody = JSONObject.parseObject(result.getResBody());
            if (200 == resultBody.getInteger("code")){
                return true;
            }
            if (401 == resultBody.getInteger("code")){
                StaticLog.error("删除文件失败，鉴权过期，进行重试调用");
                //强制刷新token
                getToken(true);
                //重新请求
                return fsRename(name,path);
            }
            else {
                StaticLog.error("删除文件失败，接口调用失败{}：",resultBody.getString("message"));
            }
        }
        catch (Exception e){
            e.printStackTrace();
            StaticLog.error("删除文件失败，接口调用异常：{}",e);
        }
        return false;
    }
}
